﻿/**
 * @file qqgame.h
 * @author zhangyufei (zhangyufei49@163.com)
 * @brief 用于和 "QQ游戏大厅" 通信的工具类
 * @date 2022-04-09
 */
#pragma once
#include <functional>
#include <cstdint>

class QQGame {
public:
    enum class MessageType {
        kNone,            // 保留字段
        kHideGame,        // 应用需要隐藏
        kShowGame,        // 应用需要前台显示出来
        kBringToTop,      // 应用需要显示在最前面
        kPayClose,        // 支付页面关闭
        kBuyVipClose,     // 购买 vip 页面关闭
        kWebClose,        // 打开的 web 页面关闭
        kLoseConnection,  // 与大厅断开连接
        kExitGame         // 调用 ExitGame 接口完成，此时不会触发 kLoseConnection 通知
    };

    using Observer = std::function<void(MessageType)>;
    using ObserverKey = void *;

    using Logger = int (*)(const char *, ...);

public:
    static QQGame *Instance();

    // 是否使用沙箱环境
    bool sandbox = true;

    // 对象析构的时候是否通知游戏大厅断开连接
    // 如果当前进程需要调起其它进程传递大厅参数，则设置该值为 false
    bool auto_exit_game = true;

    /**
     * @brief 初始化并连接大厅
     *
     * @param gameid 大厅分配给你的游戏 id
     * @param appid  大厅分配给你的应用 id
     * @param openid 大厅传递来的玩家身份 id
     * @param openkey  大厅传递来的支付参数
     * @param pfkey 大厅传递来的附加参数
     * @param port 大厅传递来的本机 websocket 端口
     */
    void Init(const char *gameid, unsigned int appid, const char *openid, const char *openkey, const char *pfkey,
              uint16_t port);

    /**
     * @brief 大厅是否已经成功初始化
     *
     * @return true
     * @return false
     */
    bool Valid() const;

    const char *openid() const;
    const char *openkey() const;
    const char *pfkey() const;
    const char *gameid() const;
    unsigned int appid() const;

    /**
     * @brief 更新 pfkey （大厅要求定期刷新 pfkey，业务层需要自行实现更新）
     *
     * @param key 新的 key
     */
    void set_pfkey(const char *key);

    ObserverKey AddObserver(Observer &&observer);
    void DelObserver(const ObserverKey key);

    /**
     * @brief 断开与游戏大厅的连接，通知大厅当前应用即将退出
     */
    void ExitGame();

    /**
     * @brief 打开大厅内置的 web 窗口（仅支持腾讯域的页面）
     *
     * @param title 窗口标题
     * @param url 要打开的页面地址
     * @param width 窗口的宽
     * @param height 窗口的高
     */
    void OpenWeb(const char *title, const char *url, uint16_t width, uint16_t height);

    /**
     * @brief 调起购买商品的窗口
     *
     * @param goods_url 由后端对接大厅支付逻辑生成的商品购买地址
     */
    void Pay(const char *goods_url);

    /**
     * @brief 调起蓝钻购买窗口
     */
    void BuyVip();

    void SetLogger(const Logger logger);

    ~QQGame();

private:
    QQGame();
    struct Impl;
    struct Impl *impl;
};
